package uy.org.softtech.cssuite.servicios;

import java.util.Locale;
import java.util.Set;

import org.springframework.security.core.userdetails.UserDetailsService;

import uy.org.softtech.cssuite.entidad.usuario.Rol;
import uy.org.softtech.cssuite.entidad.usuario.Usuario;
import uy.org.softtech.cssuite.excepciones.EntidadNoActualizadaException;
import uy.org.softtech.cssuite.excepciones.EntidadNoCreadaException;
import uy.org.softtech.cssuite.excepciones.EntidadNoEliminadaException;
import uy.org.softtech.cssuite.excepciones.EntidadNoEncontradaException;
import uy.org.softtech.cssuite.excepciones.NotificacionNoEnviadaException;
import uy.org.softtech.cssuite.excepciones.TokenExpiradoException;
import uy.org.softtech.cssuite.web.entidad.SesionUsuario;

/**
 * Interfaz por medio de la cual se acceden a los servicios relacionados a los usuarios de la aplicación.
 * Extiende de {@link UserDetailsService} para poder ser utilizada en la autenticación con Spring Security.
 * 
 * @author fabian.lobo
 */
public interface ServiciosUsuarios extends UserDetailsService {

	/**
	 * Notifica a un usuario por correo electrónico que se ha iniciado el proceso de cambio de credenciales.
	 * 
	 * @param usuario - Dirección de correo electrónico del usuario a notificar
	 * @param locale - Localización para determinar el idioma a utilizar en la notificación.
	 * @throws EntidadNoEncontradaException si no se encuentra un usuario con ese correo electrónico
	 * @throws NotificacionNoEnviadaException si la notificación por correo electrónico no pudo ser enviada.
	 * @author fabian.lobo
	 */
	void notificarCambioCredenciales(String usuario, Locale locale) throws EntidadNoEncontradaException, NotificacionNoEnviadaException;

	/**
	 * Retorna al identificador de usuario relacionado con el token presentado
	 * 
	 * @param token - Token presentado
	 * @throws TokenExpiradoException si el token ya no se encuentra vigente
	 * @author fabian.lobo
	 */
	String buscarUsuarioPorToken(String token) throws TokenExpiradoException;

	/**
	 * Retorna el registro de usuario asociado al identificador dado
	 * 
	 * @param usuario - Identificador del usuario (su correo electrónico)
	 * @throws EntidadNoEncontradaException si no se encuentra un usuario con ese correo electrónico
	 * @author fabian.lobo
	 */
	Usuario buscarUsuario(String usuario) throws EntidadNoEncontradaException;
	
	/**
	 * Actualiza los datos del usuario en la base de datos
	 * 
	 * @param usuario - Usuario con los datos a actualizar
	 * @param servicio - Nombre del servicio en donde se actualizan los datos
	 * @return el usuario actualizado
	 * @throws EntidadNoActualizadaException si no se pueden actualizar los datos en la base de datos
	 * @author fabian.lobo
	 */
	Usuario actualizar(Usuario usuario, String servicio) throws EntidadNoActualizadaException;

	/**
	 * Remuevo el token asociado al correo electrónico dado
	 * 
	 * @param email - Correo electrónico que se usó para crear el token
	 * @author fabian.lobo
	 */
	void remuevoToken(String email);

	/**
	 * Retorna el registro de usuario asociado al identificador dado
	 * 
	 * @param id - Identificador del usuario
	 * @throws EntidadNoEncontradaException si no se encuentra un usuario con ese ID
	 * @author fabian.lobo
	 */
	Usuario buscarUsuario(Long id) throws EntidadNoEncontradaException;
	
	/**
	 * Retorna una lista con información de las sesiones de usuario actualmente abiertas
	 * 
	 * @param locale - Localización para seleccionar el idioma del texto a mostrar
	 * @author fabian.lobo
	 */
	Set<SesionUsuario> listarSesiones(Locale locale);

	/**
	 * Retorna el número de usuarios que están conectados actualmente
	 * 
	 * @author fabian.lobo
	 */
	Integer usuariosConectados();

	/**
	 * Cierra la sesión de usuario identificada con el identificador dado
	 * 
	 * @param sesion - Identificador de la sesión de usuario
	 * @author fabian.lobo
	 */
	void cerrarSesion(String sesion);

	/**
	 * Valida si la sesión identificada con el ID dado está actualmente activa.
	 * 
	 * @param sesion - Identificador de la sesión
	 * @author fabian.lobo
	 */
	boolean validaSesion(String sesion);

	/**
	 * Retorna una lista con informacion de los usuarios registrados en la aplicación
	 * 
	 * @author fabian.lobo
	 */
	Set<Usuario> listarUsuarios();

	/**
	 * Retorna una lista con los diferentes roles registrados en la aplicación
	 * 
	 * @author fabian.lobo
	 */
	Set<Rol> listarRoles();

	/**
	 * Retorna el registro del rol asociado al identificador dado
	 * 
	 * @param id - Identificador del rol
	 * @throws EntidadNoEncontradaException si no se encuentra un rol con ese ID
	 * @author fabian.lobo
	 */
	Rol buscarRol(Long id) throws EntidadNoEncontradaException;

	/**
	 * Almacena los datos del nuevo usuario en la base de datos
	 * 
	 * @param usuario - Usuario con los datos a almacenar
	 * @param servicio - Nombre del servicio en donde se almacenan los datos
	 * @return el usuario almacenado
	 * @throws EntidadNoCreadaException si no se pueden almacenar los datos en la base de datos
	 * @author fabian.lobo
	 */
	Usuario crear(Usuario usuario, String servicio) throws EntidadNoCreadaException;
	
	/**
	 * Bloquea al usuario relacionado con el identificador dado
	 * 
	 * @param id - Identificador del usuario a bloquear
	 * @throws EntidadNoEncontradaException si no se encuentra un registro relacionado al identificador
	 * @throws EntidadNoActualizadaException si no se pueden actualizar los datos del usuario
	 */
	void bloquearUsuario(Long id) throws EntidadNoEncontradaException, EntidadNoActualizadaException;
	
	/**
	 * Desbloquea al usuario relacionado con el identificador dado
	 * 
	 * @param id - Identificador del usuario a desbloquear
	 * @throws EntidadNoEncontradaException si no se encuentra un registro relacionado al identificador
	 * @throws EntidadNoActualizadaException si no se pueden actualizar los datos del usuario
	 */
	void desbloquearUsuario(Long id) throws EntidadNoEncontradaException, EntidadNoActualizadaException;
	
	/**
	 * Elimina (de manera lógica) al usuario relacionado con el identificador dado
	 * 
	 * @param id - Identificador del usuario a eliminar
	 * @throws EntidadNoEncontradaException si no se encuentra un registro relacionado al identificador
	 * @throws EntidadNoEliminadaException si no se pueden actualizar los datos del usuario
	 */
	void eliminarUsuario(Long id) throws EntidadNoEncontradaException, EntidadNoEliminadaException;

}
